package liumeiya.rbac.service;

import liumeiya.rbac.domain.dto.UserDto;
import liumeiya.rbac.domain.entity.Dept;
import liumeiya.rbac.domain.entity.Role;
import liumeiya.rbac.domain.entity.User;
import liumeiya.rbac.domain.vo.Result;
import liumeiya.rbac.domain.vo.UserVo;

import java.util.Arrays;

public class UserService {

    /**
     * 实体对象的最大存储量
     * 表示系统最多可以存储的用户实体对象数量
     */
    public static int DATA_SIZE = 100;

    /**
     * 用于存储实体对象的数组
     * 数组大小为 DATA_SIZE + 1, 用于存储用户实体对象
     */
    public static User[] data = new User[DATA_SIZE + 1];

    /**
     * ID 计数器， 用于为新创建的用户分配唯一的 ID
     * 从 1 开始速增， 确保每个新创建的用户都有一个唯一的标识
     */
    public static int idCounter = 1;

    /**
     * 根据用户传输对象 (UserDto) 和用户 ID 创建一个新的用户实体对象 (User)。
     *
     * @param dto 传入的用户传输对象， 包含用户的基本信息
     * @param id 为新创建的用户实体指定的唯一 ID
     * @return 返回创建好的用户实体对象
     */
    public static User createEntity (UserDto dto, int id){
        // 使用传入的用户传输对象 (UserDto) 中的信息创建一个新的用户实体对象 (User)
        User user = new User(dto.username, dto.name, dto.mobile, dto.email, dto.deptId, dto.roleId);

        // 为新创建的用户实体对象分配唯一的 ID
        user.id = id;

        // 返回创建好的用户实体对象
        return user;
    }

    public UserService() {
    }

    /**
     * 根据用户传输对象 (UserDto) 更新用户实体对象 (User) 的属性值。
     *
     * @param dto 传入的用户传输对象，包含需要更新的用户信息
     * @param user 需要更新的用户实体对象
     */

    public static void updateEntity(UserDto dto, User user) {
        // 使用传入的用户传输对象 (UserDto), 更新用户实体对象的属性
        user.username = dto.username;
        user.name = dto.name;
        user.mobile = dto.mobile;
        user.email = dto.email;
        user.deptId = dto.deptId;
        user.roleId = dto.roleId;
    }

    /**
     * 创建一个新的用户并将其保存到数据存储中。
     *
     * 此方法会根据传入的UserDto 对象创建一个新的 User 实例， 并进行一系列的验证。
     * 它首先检查是否超过存储容量，然后验证部门和角色是否存在，最后将新创建的用户保存到数据存储中。
     *
     * @param dto 包含新用户信息的UserDto 对象
     * @return 返回一个 Result 对象， 表示操作是否成功， 并携带相应的信息和创造的用户数据
     */
    public static Result create(UserDto dto) {
        // 检查是否超出存储容量
        if (idCounter > DATA_SIZE) {
            // 如果存储容量超出限制，返回失败结果
            return Result.failure("创建失败，超出存储容量");
        }

        // 验证部门 ID 是否存在
        if (DeptService.existById(dto.deptId)) {
            // 如果指定的部门 ID 不存在， 返回失败结果
            return Result.failure("创建失败，不存在该部门");
        }

        // 验证角色 ID  是否存在
        if (RoleService.existById(dto.roleId)) {
            // 如果指定的角色 ID 不存在， 返回失败结果
            return Result.failure("创建失败，不存在该角色");
        }

        // 创建新的 User 对象
        User user = createEntity(dto, idCounter ++);

        // 将新创建的用户实体对象存储到数组中
        data[user.id] = user;

        // 返回成功结果，并携带创建成功的用户数据
        return Result.success("创建成功", user);
    }

    /**
     * 将给定的 User 对象转换为 UserVo 对象。
     * <p>
     * 此⽅法根据 User 对象的属性，构建⼀个新的 UserVo 对象，并为其赋值。
     * 其中，UserVo 中的部⻔和⻆⾊信息会通过查找相应的部⻔和⻆⾊信息来填充。
     * </p>
     *
     * @param user 需要转换的 User 对象
     * @return 返回转换后的 UserVo 对象
     */
    public static UserVo converToVo(User user) {

        // 查找部门名称
        String deptName = "";
        // 调用 DeptService 的
        Dept dept = DeptService.findById(user.deptId);
        if (dept != null) {
            //如果找到部门信息， 将部门名称赋值给 deptName
            deptName = dept.name ;
        }

        // 查找角色名称
        String roleName = "";
        // 调用 RoleService 的 findById ⽅法，根据⽤户的⻆⾊ ID 查找⻆⾊信息
        Role role = RoleService.findById(user.roleId);
        if (role != null) {
            // 如果找到⻆⾊信息，将⻆⾊名称赋值给 roleName
            roleName = role.name;
        }

        // 创建并返回 UserVo 对象
        return new UserVo(user.id, user.username, user.name,user.mobile, user.email, user.deptId, user.roleId, user.enabled, deptName, roleName);
    }

    /**
     * 获取所有有效的⽤户数据。
     * <p>
     * 本⽅法遍历存储⽤户数据的数组，将所有已创建且有效的⽤户（即 ID 对应的⽤户对象不为
     `null`）复制到⼀个临时数组中。
     * 然后返回查询成功的结果，并将该临时数组作为返回的数据。
     * </p>
     ** @return 返回⼀个 `Result` 对象，包含查询结果的状态和所有有效⽤户的数据
     */
    public static Result list() {
        // 创建⼀个临时数组，⽤于存储有效的⽤户数据，数组⼤⼩为 DATA_SIZE
        UserVo[] temp = new UserVo[DATA_SIZE];
        // ⽤于记录临时数组的实际存储⻓度
        int length = 0;

        // 遍历存储⽤户的原始数据数组，从下标 1 开始，到 idCounter -
        for (int i = 1; i< idCounter; i++) {
            // 如果当前⽤户数据不为空，则将其添加到临时数组中
            if (data[i] != null) {
                // 调⽤ convertToVo ⽅法将 User 对象转换为 UserVo 对象，并添加到临时数组中
                temp[length++] = converToVo(data[i]);
            }
        }

        // 返回查询成功的结果，并返回临时数组的有效部分
        return Result.success("查询成功", Arrays.copyOf(temp,length));
    }

    public static boolean existById(int id) {
        return id >= 1 && id < idCounter && data[id] != null;
    }

    /**
     * 更新指定 ID 的⽤户信息。
     * <p>
     * 此⽅法通过传⼊的 `UserDto` 更新⼀个已经存在的⽤户的信息。它⾸先验证⽤户 ID 是否
     有效，然后检查部⻔和⻆⾊是否存在，
     * 最后更新指定⽤户的各项属性，包括⽤户名、姓名、⼿机号、邮箱、部⻔ ID 和⻆⾊ ID。* </p>
     *
     * @param dto 包含要更新的⽤户信息的 `UserDto` 对象
     * @param id 需要更新的⽤户的 ID
     * @return 返回⼀个 `Result` 对象，表示操作是否成功，并携带相应的消息
     */
    public static Result update(UserDto dto, int id) {
        // 验证⽤户 ID 是否有效
        if (id < 1 || id >=idCounter || data[id] == null) {
            // 如果 ID ⽆效，返回失败结果
            return Result.failure("更新失败，不存在该数据");
        }

        // 验证部⻔ ID 是否存在
        if (!UserService.existById(dto.deptId)) {
            // 如果指定的部⻔ ID 不存在，返回失败结果
            return Result.failure("更新失败，不存在该部⻔");
        }

        // 验证⻆⾊ ID 是否存在
        if (!RoleService.existById(dto.roleId)) {
            // 如果指定的⻆⾊ ID 不存在，返回失败结果
            return Result.failure("更新失败，不存在该⻆⾊");
        }

        // 获取指定 ID 的⽤户对象
        User user = data[id];

        // 更新⽤户信息
        updateEntity(dto,user);

        // 返回成功结果，更新完成
        return Result.success("更新成功",null);
    }

    /*** 检查是否有⽤户拥有 roleId 对应的⻆⾊
     *
     * @param roleId ⻆⾊ ID
     * @return 如果存在⽤户具有这个⻆⾊，返回 true；否则返回 false
     */
    public static boolean roleInUse(int roleId) {
        boolean inUse = false;
        // 遍历存储⽤户数据的数组
        for (User user : data) {
            // 检查⽤户是否存在且该⽤户的⻆⾊ ID 等于传⼊的⻆⾊ ID
            if (user != null && user.roleId == roleId) {
                inUse = true;
                break;
            }
        }
        return inUse;
    }

    /*** 检查是否有⽤户拥有 deptId 对应的⻆⾊
     *
     * @param deptId 部门 ID
     * @return 如果存在⽤户具有这个部门，返回 true；否则返回 false
     */
    public static boolean deptInUse(int deptId) {
        boolean inUse = false;
        // 遍历存储⽤户数据的数组
        for (User user : data) {
            // 检查⽤户是否存在且该⽤户的⻆⾊ ID 等于传⼊的⻆⾊ ID
            if (user != null && user.deptId == deptId) {
                inUse = true;
                break;
            }
        }
        return inUse;
    }

    /**
     * 切换指定 ID 对应的数据的启⽤/禁⽤状态。
     *
     * <p>该⽅法⽤于根据⽤户传⼊的 ID 切换数据对象的 `enabled` 状态：
     * - 若 ID ⽆效（⼩于 1、超出范围或数据不存在），则返回失败结果。
     * - 若 ID 有效，则反转该数据的 `enabled` 状态，并返回相应的成功信息。</p>
     *
     * @param id 要切换状态的数据 ID
     * @return `Result` 对象，表示操作结果：
     * - 成功时返回 `"启⽤成功"` 或 `"禁⽤成功"`。
     * - 失败时返回 `"切换状态失败，不存在该数据"`。
     */
    public static Result toggle(int id) {
        // 检查 ID 是否有效
        if (id < 1 || id >= idCounter || data[id] == null) {
            return Result.failure("切换状态失败，不存在该数据");
        }

        // 反转 `enabled` 状态
        data[id].enabled = !data[id].enabled;

        // 根据新的状态返回不同的成功消息
        return Result.success(data[id].enabled ? "启⽤成功" : "禁⽤成功", null);
    }
}


